﻿//--------------------------------------------------------------------------------------------------------------------- 
// <copyright file="SynchroniseContentTypes.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Defines the AddContentTypeToList type.
// </summary>
//---------------------------------------------------------------------------------------------------------------------
namespace Collaboris.Saf.Actions.Wss.ContentType
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;

    using SharePoint.Wss.Attributes;

    using Wss;
    using Entities;
    using Engine;
    using Sharepoint.WSS.ContentTypes;
    using Utils;

    using Microsoft.SharePoint;

    [CollaborisClass(
        Title = "Synchronise Content Types",
        ReleaseStatus = ReleaseStatus.Stable,
        DisableDocumentation = false,
        ContactAuthorEmail = "Support@Collaboris.co.uk",
        Summary = "Ensures that a child content type has the same columns (fields) as the parent content type.",
        Remarks = "This action is often necessary where content types have been manually amended in the GUI." + 
                  "<br/><br/>The content types to be synchronised must be set as 'Available' in the target web.",
        ClassGuid = "{AC47BA86-4457-4447-8144-397623B8711D}"
    )
    ]
    public class SynchroniseContentTypes : WSSActionBase<ContentTypeInfo>
    {
        /// <summary>
        /// Takes the current Report and Flushes it to file.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="report">The report.</param>
        private static void FlushToFile(ContentTypeInfo entity, StringBuilder report)
        {
            string dirName = Path.GetDirectoryName(entity.ReportFileName);

            if (!String.IsNullOrEmpty(dirName) && !Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }

            if (File.Exists(entity.ReportFileName))
                File.Delete(entity.ReportFileName);

            File.WriteAllText(entity.ReportFileName, report.ToString());
        }

        /// <summary>
        /// Executes the Action using the values passed in by the Data Entity
        /// and the <see cref="SafContext"/>.
        /// </summary>
        /// <param name="context">A valid <see cref="SafContext"/> containing properties to run the Action with.</param>
        /// <param name="entity">A Valid <see cref="ContentTypeInfo"/> containing the parameters with which to run the Action with.</param>
        /// <returns>
        /// A <see cref="ProcessStatus"/> signifying the outcome of processing.
        /// </returns>
        protected override ProcessStatus DoAction(SafContext context, ContentTypeInfo entity)
        {
            this.Trace.TraceMethodStart("DoAction");

            ValidationHelper.VerifyObjectArgument(context.Site, "context.Site");

            StringBuilder report = new StringBuilder();

            try
            {
                SPContentTypeHelper.WriteReportHeader(TargetWeb, report);

                // lets do ALL the content types
                foreach (SPContentType parentType in TargetWeb.AvailableContentTypes)
                {
                    if (!string.IsNullOrEmpty(entity.ContentTypeGroupName))
                    {
                        // has a group been specified
                        if (parentType.Group == entity.ContentTypeGroupName)
                        {
                            // has a name been spec 
                            if (!string.IsNullOrEmpty(entity.ContentTypeName))
                            {
                                if (parentType.Name.ToLower() == entity.ContentTypeName.ToLower())
                                {
                                    this.PushDown(TargetWeb.Site, report, entity, parentType);
                                }
                            }
                            else
                            {
                                this.PushDown(TargetWeb.Site, report, entity, parentType);
                            }
                        }
                    }
                    else
                    {
                        // Group name has been specified
                        // has a CTYpe Name been specd ?
                        if (!string.IsNullOrEmpty(entity.ContentTypeName))
                        {
                            // does it match ?
                            if (parentType.Name.ToLower() == entity.ContentTypeName.ToLower())
                            {
                                this.PushDown(TargetWeb.Site, report, entity, parentType);
                            }
                        }
                        else
                        {
                            this.PushDown(TargetWeb.Site, report, entity, parentType);
                        }
                    }
                }
            }
            finally
            {
                SPContentTypeHelper.WriteReportFooter(TargetWeb, report);

                // Save to File
                FlushToFile(entity, report);
            }

            this.Trace.TraceMethodEnd("DoAction");

            return ProcessStatus.Success;
        }

        /// <summary>
        /// Pushes the content Type changes down the child Content Types.
        /// </summary>
        /// <param name="site">The site.</param>
        /// <param name="report">The report.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="parentType">Type of the parent.</param>
        private void PushDown(SPSite site, StringBuilder report, ContentTypeInfo entity, SPContentType parentType)
        {
            this.Trace.TraceMethodStart("PushDown");

            SPContentTypeHelper.PushChangesDown(
                entity.ReportOnlyMode.Value,
                site,
                parentType,
                report,
                entity.ExcludeSystemTypes.Value,
                entity.VerboseReporting.Value,
                entity.RemoveColumns.Value, 
                entity.CopyProperties);

            this.Trace.TraceMethodEnd("PushDown");
        }

        /// <summary>
        /// Checks the Data entity used by the Action for Validity
        /// </summary>
        /// <param name="context">The <see cref="SafContext"/> passed in by the SAF Engine.</param>
        /// <param name="entity">The data entity to Validate.</param>
        /// <param name="errors">List of <see cref="ValidationError"/>s</param>
        /// <param name="mode"><see cref="ProcessMode"/>signalling wheter we are Doing, or Undoing the action.</param>
        /// <returns>false if invalid; otherwise true.</returns>
        protected override bool IsValid(SafContext context, ContentTypeInfo entity, ref List<ValidationError> errors, ProcessMode mode)
        {
            int currentCount = errors.Count;

            // Validate each object now.
            
            ValidateStringForNull(entity.ReportFileName, "ContentTypeInfo.ReportFileName", ref errors);

            if (!entity.ExcludeSystemTypes.HasValue)
                entity.ExcludeSystemTypes = true;

            if (!entity.RemoveColumns.HasValue)
                entity.RemoveColumns = false;

            if (!entity.ReportOnlyMode.HasValue)
                entity.ReportOnlyMode = false;

            if (!entity.UpdateFields.HasValue)
                entity.UpdateFields = false;

            if (!entity.VerboseReporting.HasValue)
                entity.VerboseReporting = false;
            
            // Have we added errors ?
            return errors.Count == currentCount;
        }
    }
}
